package ace.module.upms.core.impl.service.impl;

import ace.module.common.api.model.input.AppIdListInput;
import ace.module.upms.api.model.dto.UpmsRoleDto;
import ace.module.upms.api.model.input.UpmsRoleBindAccountInput;
import ace.module.upms.core.impl.dao.entity.UpmsRole;
import ace.module.upms.core.impl.dao.entity.UpmsRoleAccount;
import ace.module.upms.core.impl.manager.UpmsRoleAccountManager;
import ace.module.upms.core.impl.manager.UpmsRoleManager;
import ace.module.upms.core.impl.service.UpmsRoleService;
import java.util.AbstractMap.SimpleEntry;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @author caspar
 * @date 2023/8/18 17:42
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class UpmsRoleServiceImpl implements UpmsRoleService {

  private final UpmsRoleManager upmsRoleManager;
  private final UpmsRoleAccountManager upmsRoleAccountManager;

  @Override
  public Map<Long, List<UpmsRoleDto>> getAccountIdAndRoleMapByUpmsAppIdAndIamAccountIdIn(
      Long upmsAppId,
      List<Long> iamAccountIds) {
    return upmsRoleManager.getAccountIdAndRoleMapByUpmsAppIdAndIamAccountIdIn(upmsAppId, iamAccountIds);
  }

  @Override
  public List<UpmsRoleDto> getByUpmsApIdAndIamAccountId(
      Long upmsAppId,
      Long iamAccountId) {
    return upmsRoleManager.getByUpmsApIdAndIamAccountId(upmsAppId, iamAccountId);
  }

  @Override
  public void saveRoleAccountRelation(AppIdListInput<UpmsRoleBindAccountInput> inputs) {
    Long upmsAppId = inputs.getAppId();

    List<Long> queryRoleIds = inputs.getData().stream()
        .map(UpmsRoleBindAccountInput::getUpmsRoleId)
        .collect(Collectors.toList());

    List<Long> queryIamAccountIds = inputs.getData().stream()
        .map(UpmsRoleBindAccountInput::getIamAccountId)
        .collect(Collectors.toList());

    List<SimpleEntry<Long, Long>> queryRoleIdAndAccountIds = inputs.getData().stream()
        .map(p -> new SimpleEntry<>(p.getUpmsRoleId(), p.getIamAccountId()))
        .collect(Collectors.toList());

    List<UpmsRole> existQueryAllRoles = upmsRoleManager.getByUpmsAppIdAndIdInAndDeleteFlagIsFalse(upmsAppId, queryRoleIds);

    List<UpmsRoleAccount> existAllQueryRoleAccounts = upmsRoleAccountManager.getByUpmsAppIdAndIamAccountIdIn(upmsAppId, queryIamAccountIds);

    List<UpmsRoleAccount> newUpmsRoleAccounts = inputs.getData()
        .stream()
        .filter(p -> this.upmsRoleManager.anyMatch(existQueryAllRoles, p.getUpmsRoleId()))
        .filter(p -> this.upmsRoleAccountManager.noneMatch(existAllQueryRoleAccounts, p.getUpmsRoleId(), p.getIamAccountId()))
        .map(upmsRoleBindAccountInput -> this.upmsRoleAccountManager.build(upmsAppId, upmsRoleBindAccountInput.getUpmsRoleId(), upmsRoleBindAccountInput.getIamAccountId()))
        .collect(Collectors.toList());

    List<Long> deleteUpmsRoleAccountIds = existAllQueryRoleAccounts.stream()
        .filter(p -> !this.upmsRoleManager.anyMatch(existQueryAllRoles, p.getRoleId()))
        .filter(p -> !this.upmsRoleAccountManager.anyMatch(existAllQueryRoleAccounts, queryRoleIdAndAccountIds))
        .map(UpmsRoleAccount::getId)
        .collect(Collectors.toList());

    this.upmsRoleAccountManager.insertNewAndDeleteByIdIn(newUpmsRoleAccounts, deleteUpmsRoleAccountIds);
  }
}
